﻿using System;
using System.IO;
using System.Threading;

using Lidgren.Network;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using System.Net;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Design;
using System.Collections;
using System.ComponentModel;
using System.Runtime.Serialization.Formatters.Binary;

namespace XnaGameServer {
    #region settings
    [Serializable]
    class gameSettings {
        public gameSettings() { }
    }
    #endregion

    class Program {
        #region API
        [StructLayout(LayoutKind.Sequential)]
        public struct PeekMsg {
            public IntPtr hWnd;
            public Message msg;
            public IntPtr wParam;
            public IntPtr lParam;
            public uint time;
            public System.Drawing.Point p;
        }
        [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool PeekMessage(out PeekMsg msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags);

        public static bool AppStillIdle {
            get {
                PeekMsg msg;
                return !PeekMessage(out msg, IntPtr.Zero, 0, 0, 0);
            }
        }
        #endregion

        public static gameSettings settings = new gameSettings();

        const string GAMEID = "DUST";
        static Form1 form;

        static NetServer server;
        static IPAddress[] addr;

        [STAThread]
        static void Main(string[] args) {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            string hostname = Dns.GetHostName();
            IPHostEntry ip = Dns.GetHostEntry(hostname);
            addr = ip.AddressList;

            Guid guid = Guid.NewGuid();

            form = new Form1();
            form.textBox1.Text = addr[0].ToString();
            form.textBox2.Text = guid.ToString();

            NetPeerConfiguration config = new NetPeerConfiguration(GAMEID);
            config.EnableMessageType(NetIncomingMessageType.DiscoveryRequest);
            config.Port = 12345;

            // create and start server
            server = new NetServer(config);
            Application.Idle += new EventHandler(Application_Idle);
            Application.Run(form);
        }

        public static void Shutdown() {
            if (server.Status == NetPeerStatus.Running) {
                server.Shutdown("app exiting");

                // supprimer l'adresse de la table
                NetGames.Services.DeleteIPAddress(form.textBox1.Text);
            }
        }

        public static void StartServer() {
            //Guid guid = Guid.NewGuid();
            server.Start();

            NetGames.Services.WriteIPAdress(GAMEID, form.textBox2.Text, form.textBox1.Text);
        }

        public static void Save() {
            try {
                Stream StreamWrite;
                SaveFileDialog DialogueSauver = new SaveFileDialog();
                DialogueSauver.Filter = "*.dust|";
                DialogueSauver.AddExtension = true;
                DialogueSauver.DefaultExt = "dust";
                DialogueSauver.FileName = "*.dust";
                if (DialogueSauver.ShowDialog() == DialogResult.OK) {
                    if ((StreamWrite = DialogueSauver.OpenFile()) != null) {
                        BinaryFormatter BinaryWrite = new BinaryFormatter();
                        BinaryWrite.Serialize(StreamWrite, settings);
                        StreamWrite.Close();
                        FileInfo fi = new FileInfo(DialogueSauver.FileName);
                        Output("Fichier " + fi.Name + " sauvegardé");
                    }
                }
            }
            catch (Exception e) {
                Output(e.Message);
            }
        }
        public static void Load() {
            try {
                Stream StreamRead;
                OpenFileDialog DialogueCharger = new OpenFileDialog();
                DialogueCharger.Filter = "*.dust|";
                DialogueCharger.AddExtension = true;
                DialogueCharger.DefaultExt = "dust";
                DialogueCharger.FileName = "*.dust";
                if (DialogueCharger.ShowDialog() == DialogResult.OK) {
                    if ((StreamRead = DialogueCharger.OpenFile()) != null) {
                        BinaryFormatter BinaryRead = new BinaryFormatter();
                        settings = (gameSettings)BinaryRead.Deserialize(StreamRead);
                        StreamRead.Close();
                        FileInfo fi = new FileInfo(DialogueCharger.FileName);
                        Output("Fichier " + fi.Name + " chargé");
                    }
                }
            }
            catch (Exception e) {
                Output(e.Message);
            }
        }

        static void Output(string text) {
            form.listBox1.Items.Add(text);
        }

        static void Application_Idle(object sender, EventArgs evt) {
            // run until escape is pressed
            while (AppStillIdle) {
                NetIncomingMessage msg;
                while ((msg = server.ReadMessage()) != null) {
                    switch (msg.MessageType) {
                        case NetIncomingMessageType.DiscoveryRequest:
                            //
                            // Server received a discovery request from a client; send a discovery response (with no extra data attached)
                            //
                            server.SendDiscoveryResponse(null, msg.SenderEndpoint);
                            break;
                        case NetIncomingMessageType.VerboseDebugMessage:
                        case NetIncomingMessageType.DebugMessage:
                        case NetIncomingMessageType.WarningMessage:
                        case NetIncomingMessageType.ErrorMessage:
                            //
                            // Just print diagnostic messages to console
                            //
                            Output(msg.ReadString());
                            break;
                        case NetIncomingMessageType.StatusChanged:
                            NetConnectionStatus status = (NetConnectionStatus)msg.ReadByte();
                            string reason = msg.ReadString();
                            Output(NetUtility.ToHexString(msg.SenderConnection.RemoteUniqueIdentifier) + " " + status + ": " + reason);
                            break;
                        case NetIncomingMessageType.Data:
                            break;
                        default:
                            Output("Unhandled type: " + msg.MessageType + " " + msg.LengthBytes + " bytes " + msg.DeliveryMethod + "|" + msg.SequenceChannel);
                            break;
                    }
                }

                // sleep to allow other processes to run smoothly
                Thread.Sleep(1);
            }
        }

        static private void synchronizeClients(NetConnection client) {
            NetOutgoingMessage om;


            //// passer en mode spectateur
            //if (server.Connections.Count > 2) {
            //    om = server.CreateMessage();
            //    om.Write((int)THNetworkMessageType.Spectator);
            //    server.SendMessage(om, client, NetDeliveryMethod.ReliableOrdered, 0);
            //}
        }
    }
}
